package com.googlecode.saucelabs;

import org.apache.http.HttpResponse;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.maven.plugin.MojoExecutionException;
import org.apache.maven.plugin.MojoFailureException;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import com.jcraft.jsch.JSch;
import com.jcraft.jsch.Session;

/**
 * Goal which touches a timestamp file.
 * 
 * @goal setup-tunnel
 * 
 * @phase pre-integration-test
 */
public class SetupTunnelMojo extends AbstractSauceMojo {
	/**
	 * @parameter default-value="${targetHost}"
	 */
	String targetHost;

	/**
	 * @parameter default-value="${targetPort}"
	 */
	int targetPort = 80;

	/**
	 * @parameter default-value="${forwardSeleniumRC}"
	 */
	private boolean forwardSeleniumRC;

	public void execute() throws MojoExecutionException, MojoFailureException {
		HttpClient httpClient = getHttpClient();
		String tunnelHost = "";

		try {
			// Part #1: Finds a tunnel
			try {
				AbstractSauceCommand<String> sauceTunnelStatusCommand = new AbstractSauceCommand<String>(
						getRequest(HttpGet.class, "/rest/%s/tunnels", username)) {
					@Override
					public String onEntityResult(HttpResponse httpResult,
							String entityResult) throws Exception {
						return onTunnelStatus(entityResult);
					}
				};

				tunnelHost = sauceTunnelStatusCommand.execute();
			} catch (Exception e) {
				throw new MojoExecutionException("Failure", e);
			}

			if (null == tunnelHost)
				throw new MojoExecutionException(
						"Unable to find any available tunnel");

			// Part #2: Proper tunnel establishment

			try {
				setupTunnel(tunnelHost);
			} catch (Exception e) {
				throw new MojoExecutionException("Failure", e);
			}
		} finally {
			httpClient.getConnectionManager().shutdown();
		}
	}

	private void setupTunnel(String tunnelHost) throws Exception {
		Session session = getJSch(username, tunnelHost);

		session.setUserInfo(new JSchAuthInfo());

		session.setConfig("StrictHostKeyChecking", "no");

		session.connect();

		JSch.setLogger(new MojoLogger());

		logMessage(
				"Connected to saucelabs ondemand tunnel @ %s as '%s' via ssh",
				tunnelHost, username);

		setSession(session);

		session.setPortForwardingR("127.0.0.1", 80, targetHost, targetPort);

		logMessage("Remote Port Forwarding (Remote Port: 80; to: %s:%d) done",
				targetHost, targetPort);

		if (forwardSeleniumRC) {
			session.setPortForwardingL("0.0.0.0", 4444, "saucelabs.com", 4444);

			logMessage(
					"Local Port Forwarding (Local Port: 4444; to: %s:%d) done",
					"saucelabs.com", 4444);
		}
	}

	private String onTunnelStatus(String entityResult) throws JSONException {
		JSONArray jsonResponseArray = new JSONArray(entityResult);

		for (int i = 0; i < jsonResponseArray.length(); i++) {
			JSONObject tunnelData = jsonResponseArray.getJSONObject(i);

			if ("running".equals(tunnelData.getString("Status")))
				return tunnelData.getString("Host");
		}

		return null;
	}
}
